package org.ecloud.oauth.server.provider;

import java.util.concurrent.TimeUnit;

import org.ecloud.common.constants.StateEnum;
import org.ecloud.core.entity.APIResult;
import org.ecloud.oauth.constants.GrantType;
import org.ecloud.oauth.constants.RedisKey;
import org.ecloud.oauth.exception.DisabledAccountException;
import org.ecloud.oauth.exception.ExcessiveAttemptsException;
import org.ecloud.oauth.exception.ExpiredAccountException;
import org.ecloud.oauth.exception.ExpiredCredentialsException;
import org.ecloud.oauth.exception.InactiveException;
import org.ecloud.oauth.exception.IncorrectCredentialsException;
import org.ecloud.oauth.exception.LockedAccountException;
import org.ecloud.oauth.exception.ManyIncorrectCredentialsException;
import org.ecloud.oauth.exception.UnknownAccountException;
import org.ecloud.redis.utils.RedisUtil;
import org.ecloud.utils.BeanUtil;
import org.ecloud.utils.StringUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

/** 
 * 用户-控制器
 *
 */
@Api(tags = "认证中心", value = "用户")
@RestController
@RequestMapping("/user")
public class UserProvider extends BaseProvider {
	
	/**
	 * 登录
	 * 
	 * @return
	 */
	@ApiOperation(value = "登录", notes = "传入用户名密码")
	@RequestMapping(value = "login", method = {RequestMethod.POST})
	public APIResult<String> login(
			@ApiParam(name = "username", value = "账号", required = true) @RequestParam(name = "username" , required = true) String username,
			@ApiParam(name = "password", value = "密码", required = true) @RequestParam(name = "password" , required = true) String password,
			@ApiParam(name = "validCode", value = "验证码", required = false) @RequestParam(name = "validcode" , required = false) String validCode
			){
		logger.debug("starting login.");
		APIResult<String> result = new APIResult<>();
		try{
			//TODO 验证码校验
			
			// 用户登录
			userService.login(username, password);
			
			// 生成登录状态
			String state = uuid();
			result.setData(state);
			
			// 存入redis
			RedisUtil.redisTemplateString.opsForValue().set(appConfig.getRedisKey(RedisKey.LOGIN_STATE, state), username, tokenConfig.getAcexpires(), TimeUnit.SECONDS);
		} catch(UnknownAccountException e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_ACCOUNT_PASSWORD.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("login failed:", e);
		} catch(InactiveException e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_ACCOUNT_INACTIVE.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("login failed:", e);
		} catch(ExpiredAccountException e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_ACCOUNT_EXPIRED.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("login failed:", e);
		} catch(ExpiredCredentialsException e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_ACCOUNT_EXPIRED_CREDENTIALS.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("login failed:", e);
		} catch(DisabledAccountException e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_ACCOUNT_DISABLED.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("login failed:", e);
		} catch(IncorrectCredentialsException e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_ACCOUNT_PASSWORD.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("login failed:", e);
		} catch(ManyIncorrectCredentialsException e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_ACCOUNT_PASSWORD.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("login failed:", e);
		} catch(ExcessiveAttemptsException e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_ACCOUNT_LOCKED.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("login failed:", e);
		} catch(LockedAccountException e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_ACCOUNT_LOCKED.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("login failed:", e);
		}catch(Exception e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_LOGIN.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("login failed:", e);
		}
		
		return result;
	}
	
	/**
	 * 登录
	 * 
	 */
	@ApiOperation(value = "登出", notes = "传入令牌")
	@RequestMapping(value = "logout", method = {RequestMethod.POST})
	public APIResult<String> logout(@ApiParam(name = "access_token", value = "令牌", required = true) @RequestParam(name = "access_token", required = true) String accessToken){
		logger.debug("logout");
		APIResult<String> result = new APIResult<>();
		
		try{
			String atkey = appConfig.getRedisKey(RedisKey.ACCESS_TOKEN, accessToken);
			if(!RedisUtil.redisTemplate.hasKey(atkey)){
				result.setCode(StateEnum.ILLEGAL_TOKEN.getCode());
				throw new RuntimeException("非法token");
			}
			
			// 多端登录处理
			Object gtObject = RedisUtil.redisTemplate.opsForHash().get(atkey, RedisKey.GRANT_TYPE);
			Object rtObject = RedisUtil.redisTemplate.opsForHash().get(atkey, RedisKey.REFRESH_TOKEN);
			Object cidObject = RedisUtil.redisTemplate.opsForHash().get(atkey, RedisKey.CLIENT_ID);
			Object unObject = RedisUtil.redisTemplate.opsForHash().get(atkey, RedisKey.USER_NAME);
			String gt = null;
			String cid = null;
			String un = null;
			if(BeanUtil.isEmpty(gtObject)){
				result.setCode(StateEnum.ILLEGAL_TOKEN.getCode());
				throw new RuntimeException("非法token");
			}
			
			String key = null;
			gt = gtObject.toString();
			logger.debug("grant type {}.", gt);
			if(GrantType.AUTHORIZATION_CODE.equalsIgnoreCase(gt)){
				if(tokenConfig.getAuthorizationCode().isSingle()){
					un = unObject.toString();
					key = appConfig.getRedisKey(RedisKey.KEY, un);
				}
			} else if(GrantType.PASSWORD_CREDENTIALS.equalsIgnoreCase(gt)){
				if(tokenConfig.getPassword().isSingle()){
					un = unObject.toString();
					key = appConfig.getRedisKey(RedisKey.KEY, un);
				}
			} else if(GrantType.CLIENT_CREDENTIALS.equalsIgnoreCase(gt)){
				if(tokenConfig.getClient().isSingle()){
					cid = cidObject.toString();
					key = appConfig.getRedisKey(RedisKey.KEY, cid);
				}
			} else {
				result.setCode(StateEnum.ILLEGAL_REQUEST.getCode());
				throw new RuntimeException("请求类型不支持！");
			}
			
			if(StringUtil.isEmpty(key)){
				RedisUtil.redisTemplate.delete(atkey);
				String rtkey = appConfig.getRedisKey(RedisKey.REFRESH_TOKEN, rtObject.toString());
				RedisUtil.redisTemplate.delete(rtkey);
			} else {
				cleanCacheKeys(key);
			}
		}catch(Exception e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_TOKEN.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("logout failed:", e);
		}
		
		return result;
	}
	
	/**
	 * 获取验证码
	 * 
	 */
	@ApiOperation(value = "获取验证码", notes = "生成验证码")
	@RequestMapping(value = "validCode", method = {RequestMethod.GET})
	public APIResult<String> validCode(){
		logger.debug("validCode");
		APIResult<String> result = new APIResult<>();
		
		try{
			//TODO 待实现
			String captcha = "1234";
			//CaptchaUtils.generateCaptcha();
			
			String key = appConfig.getRedisKey(RedisKey.LOGIN_STATE, System.currentTimeMillis()+"");
			
			result.setData(captcha);
			result.addVariable("rkey", key);
			
			// 存入redis
			RedisUtil.redisTemplateString.opsForValue().set(key, captcha, tokenConfig.getAcexpires(), TimeUnit.SECONDS);
		}catch(Exception e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_VALID_CODE.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("logout failed:", e);
		}
		
		return result;
	}
	
}
